package ControllerModule

import (
	"net/http"
	"frame/utils/PropertiesUtils"
	"frame/utils/FileUtils"
	"frame/logger/HLogger"
	"tools/IDGeneratorTools"
	"strconv"
	"errors"
	"strings"
	"frame/utils/StringUtils"
	"regexp"
	"reflect"
	"frame/controller/ControllerModule/ControllerParam"
	"frame/controller/ControllerModule/ModelAndView"
	"html/template"
)

type ControllerModule struct {
	Name string
	Path string
	Subpath map[string]interface{}
}



var controllerModules = make(map[string]ControllerModule)
var funcMappings = make(map[string]interface{})

var logger = HLogger.GetHLogger("ControllerModule")

/**
注册一个controller,将其内部的方法映射到funcMappings中
 */
func RegisterControllerModule(controllerModule ControllerModule)(bool,error){
	controllerModules[controllerModule.Name]=controllerModule
	var name = controllerModule.Name
	var path = controllerModule.Path
	for sp,fc := range controllerModule.Subpath {
		var matchpath = path+sp //例如path = /AController   sp = /BMethod.do  则真是访问路径位 http://x.x.x.x/AController/BMethod.do
		//检查路径合法性
		if(!checkMatchPathIsOK(matchpath)){
			return false,errors.New("注册name["+name+"]的controller时,访问路径matchpath["+matchpath+"]不合法^\\{[A-Za-z][0-9A-Za-z]*\\}$")
		}
		if(funcMappings[matchpath]!=nil){
			return false,errors.New("注册name["+name+"]的controller时,访问路径matchpath["+matchpath+"]的函数已存在")
		}else{
			funcMappings[matchpath]=fc
		}
	}
	return true,nil
}

func GetControllerModulesCount()(int){
	return len(controllerModules)
}

func Handler(path string,req *http.Request,respwriter http.ResponseWriter){
	//-1 生成log上下文
	var txnid,_ = IDGeneratorTools.CreateSimpleUint64()
	var txnContext = HLogger.TxnContext{Txnid:StringUtils.StrRightAlign(strconv.Itoa(int(txnid)),8)}
	//0判断是否是静态资源
	var root,_ = PropertiesUtils.GetConfig("server","root","html")
	if(FileUtils.CheckFileIsExistAndIsFile(root+path)){
		var content,err = FileUtils.ReadByteFile(root+path)
		if(err!=nil){
			logger.ErrorWithTxnContext(txnContext,"文件读取错误")
		}
		respwriter.Write(content)
		return
	}else{
		//1寻找path对应的controller，绝对路径查询
		for mp,fc := range funcMappings {
			if(mp==path){
				//创建空的pathparam
				var pathparam = make(map[string]string)
				//执行函数
				var execfuncresult = execfunc(fc,req,respwriter,pathparam,txnContext)
				//解析视图
				var viewres,err = viewresolver(fc,req,respwriter,pathparam,txnContext,execfuncresult)
				if(err!=nil){
					logger.ErrorWithTxnContext(txnContext,err.Error())
				}
				if(viewres){
					logger.DebugWithTxnContext(txnContext,"视图解析成功")
				}
				return
			}
		}
		//2寻找path对应的controller，匹配路径查询
		for mp,fc := range funcMappings {
			if(isPairPath(mp,path)){
				//创建空的pathparam并赋值
				var pathparam = make(map[string]string)
				parsePathParam(pathparam,mp,path)
				//执行函数
				var execfuncresult = execfunc(fc,req,respwriter,pathparam,txnContext)
				//解析视图
				var viewres,err = viewresolver(fc,req,respwriter,pathparam,txnContext,execfuncresult)
				if(err!=nil){
					logger.ErrorWithTxnContext(txnContext,err.Error())
				}
				if(viewres){
					logger.DebugWithTxnContext(txnContext,"视图解析成功")
				}
				return
			}
		}
	}
}

func execfunc(fc interface{},req *http.Request,respwriter http.ResponseWriter,pathparam map[string]string,txnContext HLogger.TxnContext) []interface{}{
	//0组装参数
	//获取fc函数的参数数量
	var fc_functionsign = reflect.TypeOf(fc)
	var fcnumin = fc_functionsign.NumIn()
	var callparam = make([]reflect.Value,0,fcnumin)
	for i:=0;i<fcnumin;i++{
		var typeofparami = fc_functionsign.In(i)
		var paramsign = StringUtils.Trim(typeofparami.String())
		if(paramsign =="ControllerParam.HttpRequest"){
			callparam = append(callparam, reflect.ValueOf(req))
		}
		if(paramsign =="ControllerParam.HttpRequestWriter"){
			callparam = append(callparam, reflect.ValueOf(respwriter))
		}
		if(paramsign =="ControllerParam.PathParameters"){
			callparam = append(callparam, reflect.ValueOf(pathparam))
		}
		if(paramsign =="ControllerParam.RequestBody"){
			buf := make([]byte, 1024)
			result := make([]byte, 1024)
			for {
				_, err := req.Body.Read(buf)
				if err != nil {
					break
				}
				result = append(result, buf...)
			}
			callparam = append(callparam, reflect.ValueOf(ControllerParam.RequestBody(string(result))))
		}
		if(paramsign =="ControllerParam.TxnContext"){
			callparam = append(callparam, reflect.ValueOf(ControllerParam.TxnContext(txnContext)))
		}
	}

	//1函数调用
	var result []reflect.Value = reflect.ValueOf(fc).Call(callparam)

	//fmt.Println(result)
	//2组装结果并返回
	var execfuncresult = make([]interface{},0, len(result))
	for _,v :=range result {
		execfuncresult = append(execfuncresult,v.Interface())
	}
	return execfuncresult
}

/**
判断realpath是否符合matchpath的格式
match有如下格式
/a/b  匹配/a/b
/{c}/b 匹配 /[0-9A-Za-z]* /b 的字符串
 */
func isPairPath(matchpath string,realpath string)(bool){
	var matchpath_groups = strings.Split(StringUtils.Trim(matchpath),"/")
	var realpath_groups = strings.Split(StringUtils.Trim(realpath),"/")
	if(len(matchpath_groups)!=len(realpath_groups)){
		return false
	}
	var result = true
	for i:=0;i<len(matchpath_groups);i++ {
		if(matchpath_groups[i] == realpath_groups[i]){
			continue
		}
		matchpath_groups_i_trim := StringUtils.Trim(matchpath_groups[i])
		var regExp = regexp.MustCompile(`^\{[A-Za-z][0-9A-Za-z]*\}$`)
		if(regExp.Match([]byte(matchpath_groups_i_trim))){
			continue
		}else{
			result = false
			break
		}
	}
	return result;
}
func checkMatchPathIsOK(matchpath string)(bool){
	var matchpath_groups = strings.Split(StringUtils.Trim(matchpath),"/")
	var result = true
	for i:=0;i<len(matchpath_groups);i++ {
		matchpath_groups_i_trim := StringUtils.Trim(matchpath_groups[i])
		if(StringUtils.IsEmpty(matchpath_groups_i_trim)){
			continue
		}
		var regExp = regexp.MustCompile(`^\{?[A-Za-z][0-9A-Za-z]*\}?$`)
		if(regExp.Match([]byte(matchpath_groups_i_trim))){
			continue
		}else{
			result = false
			break
		}
	}
	return result;
}
func parsePathParam(pathparam map[string]string,matchpath string,realpath string){
	var matchpath_groups = strings.Split(StringUtils.Trim(matchpath),"/")
	var realpath_groups = strings.Split(StringUtils.Trim(realpath),"/")
	for i:=0;i<len(matchpath_groups);i++ {
		matchpath_groups_i_trim := StringUtils.Trim(matchpath_groups[i])
		if(matchpath_groups_i_trim[0]=='{'&&matchpath_groups_i_trim[len(matchpath_groups_i_trim)-1]=='}'){
			matchpath_groups_i_trim_key := matchpath_groups_i_trim[1:len(matchpath_groups_i_trim)-2]
			realpath_groups_i := realpath_groups[i]
			pathparam[matchpath_groups_i_trim_key]=realpath_groups_i
		}

	}
}

/**
视图解析器
 */
func viewresolver(fc interface{},req *http.Request,respwriter http.ResponseWriter,pathparam map[string]string,txnContext HLogger.TxnContext,execfuncresult []interface{})(bool,error){
	//1无返回值不处理
	if(len(execfuncresult)==0){
		return true,nil
	}
	//初始化modelAndView
	var modelAndView ModelAndView.ModelAndView
	if(len(execfuncresult)==1){
		var r0 = execfuncresult[0]
		var r0type = reflect.TypeOf(r0).String()
		if(r0type=="string"){
			//2返回string，则将request+,session属性封装为modelandview，送入下一步展示
			modelAndView = ModelAndView.CreateModelAndView("default",nil)
			modelAndView.Viewname=reflect.ValueOf(r0).String()
		} else if(r0type=="ModelAndView.ModelAndView"){
			//3返回modelanview，送入下一步展示
			modelAndView = reflect.ValueOf(r0).Interface().(ModelAndView.ModelAndView)
		} else{
			return false,errors.New("执行funcmethod时，返回值只允许[无][string][ModelAndView.ModelAndView]三种情况")
		}
	}else{
		return false,errors.New("执行funcmethod时，返回值只允许[无][string][ModelAndView.ModelAndView]三种情况")
	}
	modelAndView.AddSessionAttribute(req)//session优先级最低
	modelAndView.AddRequestAttribute(req)//request优先级较高,//modelAndView的返回值优先级最高
	//4modelandview解析，解析程序？modelandview属性
	_,viewprocess_err := viewprocess(fc,req,respwriter,pathparam,txnContext,modelAndView)
	if(viewprocess_err!=nil){
		logger.ErrorWithTxnContext(txnContext,viewprocess_err.Error())
	}
	return true,nil
}

func viewprocess(fc interface{},req *http.Request,respwriter http.ResponseWriter,pathparam map[string]string,txnContext HLogger.TxnContext,modelandview ModelAndView.ModelAndView)(bool,error){
	//仅支持templete解析器
	var viewname = modelandview.Viewname
	if(strings.Index(strings.ToUpper(viewname),"TEMPLATE:")==0||strings.Index(viewname,":")<0){
		//如果viewname是t:开头或者view中没有:，则默认使用go templete
		//创建template
		var t = template.New(viewname)
		//加载template文件
		var templatepath,_ = PropertiesUtils.GetConfig("server","templatepath","template")
		if(!strings.HasSuffix(templatepath,FileUtils.GetFileSeparator())){
			templatepath = templatepath+FileUtils.GetFileSeparator()
		}
		var templatefilesuffix,_ = PropertiesUtils.GetConfig("server","templatefilesuffix",".template")
		var realviewpath = templatepath+viewname+templatefilesuffix
		var t_content,err = FileUtils.ReadFile(realviewpath)
		if(err!=nil){
			return false,errors.New("根据realviewpath["+realviewpath+"]获取view模板失败")
		}
		t,_ = t.Parse(t_content)
		err = t.Execute(respwriter, modelandview)
		if(err != nil){
			return false,errors.New("realviewpath["+realviewpath+"]解析失败")
		}
		return true,nil
	}else{
		return false,errors.New("不支持的viewname["+viewname+"]")
	}
}